﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Drawing;
using mKoenig.PictureSlide.Properties;

namespace mKoenig.PictureSlide
{
  public delegate void ShutDownDelegate();

  /// <summary>
  /// this holds the screensaver for all screens
  /// </summary>
  public class Screensaver
  {
    #region imports

    static int WH_MOUSE_LL = 14;
    static int WM_LBUTTONUP = 0x0202;

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    static extern IntPtr GetModuleHandle(string moduleName);
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    public static extern int UnhookWindowsHookEx(IntPtr hhook);
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, uint wParam, IntPtr lParam);

    delegate IntPtr HookProc(int nCode, uint wParam, IntPtr lParam);
    #endregion

    private HookProc hookProc;
    private IntPtr hook;
    private Point mouseLocation;
    private bool isActive;

    private Settings setting = Settings.Default;
    private FileHandling fileHandler;
    private int minFiles = 10;

    private bool shuttingDown = false;
    private int screenCount = 0;
    private Main[] sf;

    public ShutDownDelegate ShutDownDel;

    public void RunMe()
    {
      fileHandler = FileHandling.GetInstance();
      Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Start screensaver, wait for files");
    
      DateTime start = DateTime.Now;
      TimeSpan span = DateTime.Now - start;

      while ((fileHandler.Count < minFiles) || (span.TotalSeconds < 2))
      {
        span = DateTime.Now - start;
        if (span.TotalSeconds > setting.MaxPrefetchTime)
        {
          MessageBox.Show("not enough picutes found in path : " + setting.PicturePath + ")");
          break;
        }
      }

      Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Start screensaver files now " + fileHandler.Count.ToString());
      if (fileHandler.Count >= minFiles)
      {
        hookProc = new HookProc(LowLevelMouseProc);
        hook = SetWindowsHookEx(WH_MOUSE_LL, hookProc, GetModuleHandle(null), 0);

        ShutDownDel = new ShutDownDelegate(ShutDown);

        screenCount = Screen.AllScreens.Length;
        sf = new Main[screenCount];

        Cursor.Hide();

        int i = 0;
        for (i = 0; i < screenCount; i++)
        {
          sf[i] = new Main(i);
          sf[i].Text = "Screensaver";
          sf[i].ShowInTaskbar = false;

          sf[i].Size = Screen.AllScreens[i].Bounds.Size;
          sf[i].Left = Screen.AllScreens[i].Bounds.Left;
          sf[i].Top = Screen.AllScreens[i].Bounds.Top;

          sf[i].MaximumSize = sf[i].Size;
          sf[i].MinimumSize = sf[i].Size;

          sf[i].StartPosition = FormStartPosition.Manual;
          //sf[i].TopMost = true;
          sf[i].Show();
        }

        while (!shuttingDown)
        {
          for (i = 0; i < screenCount; i++)
          {
            sf[i].updateTimer();
          }
          Application.DoEvents();
          Thread.Sleep(20);
        }

        Cursor.Show();
        UnhookWindowsHookEx(hook);

        CloseAllScreens();
      }
      else
      {
        // not enough files
        Application.Exit();
      }
    }

    public void ShutDown()
    {
      shuttingDown = true;
    }
    private void CloseAllScreens()
    {
      if (screenCount > 0)
      {
        screenCount = 0;
        for (int i = 0; i < Screen.AllScreens.Length; i++)
        {
          try
          {
            if (sf[i].Created == true && (sf[i].Visible == true))
            {
              sf[i].Close();
              Application.DoEvents();
            }
          }
          catch (Exception ex)
          {
            if (ex.Message != "LocalDataStoreSlot storage has been freed.")
              throw ex;
          }
        }
      }
    }

    private IntPtr LowLevelMouseProc(int nCode, uint wParam, IntPtr lParam)
    {
      if (wParam == WM_LBUTTONUP)
      {
        ShutDown();
      }
      else
      {
        // get the current mouse position
        Point mousePos = Cursor.Position;

        if (!isActive)
        {
          mouseLocation = mousePos;
          isActive = true;
        }
        else
        {
          // If the mouse has moved significantly since first call, close.
          if ((Math.Abs(mousePos.X - mouseLocation.X) > 10) ||
              (Math.Abs(mousePos.Y - mouseLocation.Y) > 10))
          {
            ShutDown();
          }
        }
      }

      return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
    }
  }
}
